package store

import (
	"codejy/structdef"
	"codejy/utils"
	"fmt"
)

// 注册变量
func RegisterVariable(threadStore *structdef.ThreadStore, varDef structdef.VarDefinition) {
	currentEnv := threadStore.CurrentEnv
	RegisterVariableScope(threadStore, currentEnv, varDef)
}
func RegisterVariableScope(threadStore *structdef.ThreadStore, currentEnv string, varDef structdef.VarDefinition) {
	//判断做用域是否存在
	if _, ok := threadStore.VariableStoreMap[currentEnv]; !ok {
		threadStore.VariableStoreMap[currentEnv] = make(map[string]structdef.VarDefinition)
	}
	//判断变量是否已经注册,那么就报错
	if v, ok := threadStore.VariableStoreMap[currentEnv][varDef.Name]; ok {
		switch v.Extend {
		//如果是函数返回值,那么就修改变量,因为返回值就在函数返回的时候用一次后面就没什么用了
		case "func->to":
			break
		default:
			var errorStr = fmt.Sprintf("错误::::::%s变量已经注册,错误代码: %s", varDef.Name, threadStore.Code)
			panic(errorStr)
		}
	}
	threadStore.VariableStoreMap[currentEnv][varDef.Name] = varDef

	utils.DebugLog("变量注册后的信息", func() {
		PrintVariable(threadStore)
	})
}

// 修改变量
func ModifyVariable(threadStore *structdef.ThreadStore, varDef structdef.VarDefinition) {
	currentEnv := threadStore.CurrentEnv
	ModifyVariableScope(threadStore, currentEnv, varDef)

}
func ModifyVariableScope(threadStore *structdef.ThreadStore, currentEnv string, varDef structdef.VarDefinition) {
	//判断变量是否存在,如果不存在,那么就报错没有找到变量
	if _, ok := threadStore.VariableStoreMap[currentEnv][varDef.Name]; !ok {
		var errorStr = fmt.Sprintf("错误::::::没有找到变量,错误代码: %s", varDef)
		panic(errorStr)
	}

	//修改变量
	threadStore.VariableStoreMap[currentEnv][varDef.Name] = varDef
}

func CreateAndModifyVariable(threadStore *structdef.ThreadStore, varDef structdef.VarDefinition) {
	currentEnv := threadStore.CurrentEnv
	CreateAndModifyVariableScope(threadStore, currentEnv, varDef)
}
func CreateAndModifyVariableScope(threadStore *structdef.ThreadStore, currentEnv string, varDef structdef.VarDefinition) {
	//判断变量是否存在,如果不存在,那么就创建变量
	if _, ok := threadStore.VariableStoreMap[currentEnv][varDef.Name]; !ok {
		RegisterVariableScope(threadStore, currentEnv, varDef)
		return
	}
	//修改变量
	ModifyVariableScope(threadStore, currentEnv, varDef)
}

// 获取变量
func GetVariable(threadStore *structdef.ThreadStore, varName string) (structdef.VarDefinition, bool) {
	//获取当前环境
	currentEnv := threadStore.CurrentEnv
	//判断变量是否存在
	if _, ok := threadStore.VariableStoreMap[currentEnv][varName]; !ok {
		//判断父作用域是否存在
		if _, ok1 := threadStore.VariableStoreMap[threadStore.ParentEnv][varName]; ok1 {
			//获取父作用域变量
			return threadStore.VariableStoreMap[threadStore.ParentEnv][varName], true
		}
		return structdef.VarDefinition{}, false
	}
	//获取变量
	return threadStore.VariableStoreMap[currentEnv][varName], true
}

// 获取指定作用域的变量
func GetVariableScope(threadStore *structdef.ThreadStore, scope, varName string) (structdef.VarDefinition, bool) {

	//判断变量是否存在
	if _, ok := threadStore.VariableStoreMap[scope][varName]; !ok {
		return structdef.VarDefinition{}, false
	}
	//获取变量
	return threadStore.VariableStoreMap[scope][varName], true
}

// 获取全局变量
func GetGlobalVariable(threadStore *structdef.ThreadStore, varName string) (structdef.VarDefinition, bool) {
	//获取主文件全局环境
	globalEnv := threadStore.GlobalEnv
	//判断变量是否存在
	if _, ok := threadStore.VariableStoreMap[globalEnv][varName]; !ok {
		return structdef.VarDefinition{}, false
	}
	//获取变量
	return threadStore.VariableStoreMap[globalEnv][varName], true
}

// 注册变量到父作用域
func RegisterVariableToParent(threadStore *structdef.ThreadStore, currentParentEnv string, varDef structdef.VarDefinition) {
	env := threadStore.CurrentEnv //获取当前作用域
	//设置当前作用域为父作用域
	AddCurrentEnv(threadStore, currentParentEnv)
	RegisterVariable(threadStore, varDef)
	//还原当前作用域
	AddCurrentEnv(threadStore, env)
}

// 删除指定作用域指定变量
func DeleteVariable(threadStore *structdef.ThreadStore, varName string) {
	//获取当前环境
	currentEnv := threadStore.CurrentEnv
	DeleteVariableScope(threadStore, currentEnv)
}

// 删除指定作用域
func DeleteVariableScope(threadStore *structdef.ThreadStore, currentEnv string) {
	//判断变量是否存在
	if _, ok := threadStore.VariableStoreMap[currentEnv]; !ok {
		return
	}

	//删除变量
	delete(threadStore.VariableStoreMap, currentEnv)
	utils.DebugLog("删除指定作用域后的信息", func() {
		PrintVariable(threadStore)
	})
}

// 打印线程内的变量情况
func PrintVariable(threadStore *structdef.ThreadStore) {
	for currentEnv, v1 := range threadStore.VariableStoreMap {
		for varName, v2 := range v1 {
			fmt.Printf("线程Id:%s ,作用域:%s ,变量名:%s ,变量定义:%s \n", threadStore.ThreadId, currentEnv, varName, v2)
		}
	}

}

// 获取当前作用域的变量
func GetCurrentEnvVariable(threadStore *structdef.ThreadStore) map[string]structdef.VarDefinition {

	//获取当前环境
	currentEnv := threadStore.CurrentEnv
	//判断变量是否存在
	if _, ok := threadStore.VariableStoreMap[currentEnv]; !ok {
		return make(map[string]structdef.VarDefinition)
	}
	return threadStore.VariableStoreMap[currentEnv]
}

// 获取所有指定线程当前作用域的指定类型变量
func GetShareTypeVariable(threadStore *structdef.ThreadStore, varName string, varType int) (structdef.VarDefinition, bool) {

	currentEnv := threadStore.CurrentEnv
	m := threadStore.VariableStoreMap[currentEnv]
	for k, v := range m {
		if v.Name == varName && v.VarType == varType {
			return m[k], true
		}
	}
	return structdef.VarDefinition{}, false
}

// 获取3个层级的变量,局部变量,类变量,全局变量
func Get3LevelVariable(threadStore *structdef.ThreadStore, name string) (structdef.VarDefinition, string, bool) {

	//获取当前环境
	var scope = threadStore.CurrentEnv
	varValue, b := GetVariable(threadStore, name)
	if !b { //如果局部变量不存在,则获取类变量
		//获取当前实例
		currentInstanceAddress := threadStore.CurrentInstanceAddress
		if currentInstanceAddress != "" {
			maps, b1 := GetInstanceProp(threadStore, currentInstanceAddress)
			if b1 { //获取实例属性
				_, b2 := maps[name]
				if b2 { //如果存在,则返回
					return maps[name], currentInstanceAddress, true
				}
			}
			//获取父类实例属性
			//当前实例拿不到去获取父实例
			parentInstanceAddress := threadStore.ParentInstanceAddress
			if parentInstanceAddress != currentInstanceAddress {
				maps, b1 = GetInstanceProp(threadStore, parentInstanceAddress)
				if b1 { //获取实例属性
					_, b2 := maps[name]
					if b2 { //如果存在,则返回
						return maps[name], currentInstanceAddress, true
					}
				}
			}
		}
		//类型不存在获取全局变量
		parentScope := threadStore.GlobalEnv
		varValue, b = GetVariableScope(threadStore, parentScope, name)
		if !b {
			return structdef.VarDefinition{}, parentScope, false
		}
		return varValue, parentScope, true
	}
	return varValue, scope, true
}
